#include "DXManager.h"
// ***********************************************************************************
// Construction : 
// Effect init variable for control directX device
//  
// ***********************************************************************************

DXManager::DXManager(HWND hwnd,HINSTANCE hInstance,int _Width,int _Height,bool _IsFull)
{
	m_hInstance=hInstance;
	m_hWnd=hwnd;
	m_pScreenWidth=_Width;
	m_pScreenHeight=_Height;
	m_pIsFullScreen=_IsFull;

	m_pD3D=NULL;
	m_pD3DDevice=NULL;
	m_pD3DInput=NULL;
	m_pKeyboardDevice=NULL;
	m_pSprite=NULL;
	m_pBackBuffer=NULL;
}
void DXManager::Destroy()
{
	if(m_pD3DDevice!=NULL)
	{
		m_pD3DDevice->Release();
	}
	if(m_pD3D!=NULL)
	{
		m_pD3D->Release();
	}
}
bool DXManager::Init()
{
	HRESULT               hResult;
	D3DPRESENT_PARAMETERS present;
	D3DCAPS9              caps;
	D3DDISPLAYMODE        currentMode;

	if(NULL==(m_pD3D=Direct3DCreate9(D3D_SDK_VERSION)))
	{
		TraceGame(L"(INFO)INIT DIRECTX :Hardware isn't support depth buffer");
		return false;
	}
	ZeroMemory(&present,sizeof(present));
	m_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &currentMode);
	present.BackBufferFormat = currentMode.Format;
	present.SwapEffect=D3DSWAPEFFECT_DISCARD;
	present.Windowed=present.Windowed=!m_pIsFullScreen;;
	present.AutoDepthStencilFormat = FindDepthStencilFormat( D3DADAPTER_DEFAULT, currentMode, D3DDEVTYPE_HAL );
	present.EnableAutoDepthStencil=true;
	present.PresentationInterval=D3DPRESENT_INTERVAL_IMMEDIATE;
	
	//present.BackBufferCount=D3DSWAPEFFECT_DISCARD;
	//present.BackBufferWidth=WINDOW_WIDTH;
	//present.BackBufferHeight=WINDOW_HEIGHT;
	//present.hDeviceWindow=m_hWnd;

	// Set Creation Flags
	unsigned long ulFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

	// Check if Hardware T&L is available
	ZeroMemory( &caps, sizeof(D3DCAPS9) );
	m_pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps );
	if ( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) 
		ulFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
	
	// Try to use hardware device
	if( FAILED( hResult = m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, ulFlags, &present, &m_pD3DDevice ) ) ) 
	{
		// Find REF depth buffer format
		present.AutoDepthStencilFormat = FindDepthStencilFormat( D3DADAPTER_DEFAULT, currentMode, D3DDEVTYPE_REF );

		// Check if Hardware T&L is available
		ZeroMemory( &caps, sizeof(D3DCAPS9) );
		ulFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
		m_pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, &caps );
		if ( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) ulFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;

		// Attempt to create a REF device
		if( FAILED( hResult = m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, m_hWnd, ulFlags, &present, &m_pD3DDevice ) ) ) 
		{
			return false;
		}
		TraceGame(L"(INFO) INIT DIRECTX : using HEL");

	} 
	TraceGame(L"(INFO) INIT DIRECTX : using HAL");
	TraceGame(L"(INFO) INIT DIRECTX : init directX successful");

	
	D3DXCreateSprite(m_pD3DDevice,&m_pSprite);
	if(m_pSprite==NULL)
		return false;
	return true;
}
bool DXManager::InitKeyboardDevice()
{
	HRESULT hResult=DirectInput8Create(m_hInstance,DIRECTINPUT_VERSION,IID_IDirectInput8, (VOID**)&m_pD3DInput, NULL);
	if(hResult!=DI_OK)
		return false;
	hResult=m_pD3DInput->CreateDevice(GUID_SysKeyboard, &m_pKeyboardDevice, NULL); 
	if(hResult!=DI_OK)
		return false;
	hResult=m_pKeyboardDevice->SetDataFormat(&c_dfDIKeyboard);
	if(hResult!=DI_OK)
		return false;
	DIPROPDWORD dipdw;
	dipdw.diph.dwSize=sizeof(DIPROPDWORD);
	dipdw.diph.dwHeaderSize=sizeof(DIPROPHEADER);
	dipdw.diph.dwObj=0;
	dipdw.diph.dwHow=DIPH_DEVICE;
	dipdw.dwData= KEYBOARD_BUFFER_SIZE;
	TraceGame(L"Set proferties Keyboard sucessful ");
	// set proferty sucessful
	hResult=m_pKeyboardDevice->SetProperty(DIPROP_BUFFERSIZE,&dipdw.diph);
	if(hResult!=DI_OK)
		return false;
	hResult=m_pKeyboardDevice->Acquire();
	if(hResult!=DI_OK)
		return false;
	TraceGame(L" Acquite Keyboard sucessful ");
	return true;
}
void DXManager::BeginRender()
{
	if(m_pD3DDevice==NULL)
		return;
	m_pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,255),1.0f,0);
	m_pD3DDevice->BeginScene();
}
void DXManager::EndRender()
{
	m_pD3DDevice->EndScene();
}
void DXManager::ClearScreen()
{
	m_pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(200,0,0),1.0f,0);
}
IDirect3DSurface9 *DXManager::CreateSurfaceFromFile(std::string filename)
{
	
	HRESULT hResult;
	IDirect3DSurface9 *surface;
	D3DXIMAGE_INFO imageInfo;
	hResult=::D3DXGetImageInfoFromFile(filename.c_str(),&imageInfo);
	if(FAILED(hResult))
		return NULL;
	hResult= m_pD3DDevice->CreateOffscreenPlainSurface(imageInfo.Width,imageInfo.Height,D3DFMT_X8R8G8B8,D3DPOOL_DEFAULT,&surface,NULL);
	if(FAILED(hResult))
		return NULL;
	hResult=::D3DXLoadSurfaceFromFile(surface,NULL,NULL,filename.c_str(),NULL,D3DX_DEFAULT,D3DCOLOR_ARGB(255,255,255,255),NULL);
	if(FAILED(hResult))
		return NULL;
	return surface;
}
void DXManager::ShowSurface(IDirect3DSurface9 *surface,const RECT *srcrect,const RECT *desRect)
{
	m_pD3DDevice->StretchRect(surface,srcrect,m_pBackBuffer,desRect,D3DTEXF_NONE);
}

LPDIRECT3DDEVICE9 DXManager::GetD3DDDevice()
{
	if(m_pD3DDevice!=NULL)
		return m_pD3DDevice;
	return NULL;
}
LPD3DXSPRITE DXManager::GetD3DXSprite()
{
	if(m_pSprite!=NULL)
		return m_pSprite;
	return NULL;
}

void DXManager::BeginSprite()
{
	m_pSprite->Begin(D3DXSPRITE_ALPHABLEND);
}
void DXManager::EndSprite()
{
	m_pSprite->End();
}
DXManager::~DXManager(void)
{
	Destroy();
}

/*LPDIRECT3DTEXTURE9 CreateTextture(char filename[],int color)
{
	D3DXIMAGE_INFO Info;
	LPDIRECT3DTEXTURE9 texture;
	D3DXGetImageInfoFromFile(filename,&Info);
	D3DXCreateTextureFromFileEx
	(	
		
		m_pD3DDevice,
		filename,
		Info.Width,
		Info.Height,
		1,
		D3DUSAGE_DYNAMIC,
		D3DFMT_UNKNOWN,
		D3DPOOL_DEFAULT,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		color,
		&Info,
		NULL,
		&texture
	);
	return texture;
}*/
LPDIRECT3DVERTEXBUFFER9 DXManager::createVertexBuffer(int size,DWORD FVF)
{
	LPDIRECT3DVERTEXBUFFER9 buffer;
	HRESULT hResult=m_pD3DDevice->CreateVertexBuffer(size,0,FVF,D3DPOOL_DEFAULT,&buffer,NULL);
	if(FAILED(hResult))
		return NULL;
	return buffer;
}
LPDIRECT3DINDEXBUFFER9 DXManager::createIndexBuffer(int size,DWORD FVF)
{
	LPDIRECT3DINDEXBUFFER9 indexBuffer;
	HRESULT hResult=m_pD3DDevice->CreateIndexBuffer(size,0,D3DFMT_INDEX16,D3DPOOL_DEFAULT,&indexBuffer,NULL);
	if(FAILED(hResult))
		return NULL;
	return indexBuffer;
}

/****************************************************************************************/
/******************			CREATE CAMERA			*************************************/
/****************************************************************************************/
void DXManager::CreateCamera(float nearClip,float farClip)
{
	D3DXMatrixPerspectiveFovLH(&m_MatProj,D3DX_PI/3,m_pScreenWidth/m_pScreenHeight,nearClip,farClip);
	m_pD3DDevice->SetTransform(::D3DTS_PROJECTION,&m_MatProj);
}

/****************************************************************************************/
/******************			MOVE CAMERA				*************************************/
/****************************************************************************************/
void DXManager::MoveCamera(D3DXVECTOR3 vec)
{
	m_VecCameraPos=vec;
}
/****************************************************************************************/
/******************			 POINT CAMERA			*************************************/
/****************************************************************************************/
void DXManager::PointCamera(D3DXVECTOR3 vec)
{
	m_VecCameraLook=vec;
	D3DXMatrixLookAtLH(&m_MatView,&m_VecCameraPos,&m_VecCameraLook,&D3DXVECTOR3(0.0f,1.0f,0.0f));
	m_pD3DDevice->SetTransform(D3DTS_VIEW,&m_MatView);

}


D3DFORMAT  DXManager::FindDepthStencilFormat( ULONG AdapterOrdinal, D3DDISPLAYMODE Mode, D3DDEVTYPE DevType )
{
	// Check 32bit depth buffer available
	if (SUCCEEDED( m_pD3D->CheckDeviceFormat(AdapterOrdinal, DevType, Mode.Format, D3DUSAGE_DEPTHSTENCIL , D3DRTYPE_SURFACE , D3DFMT_D32 )))
	{
		if (SUCCEEDED( m_pD3D->CheckDepthStencilMatch ( AdapterOrdinal, DevType, Mode.Format, Mode.Format, D3DFMT_D32 ))) return D3DFMT_D32;
		TraceGame(L"(INFO)INIT DIRECTX : Hardware is support 32 bit depth buffer");
	} 

	// Check 24bit depth buffer available
	if (SUCCEEDED( m_pD3D->CheckDeviceFormat(AdapterOrdinal, DevType, Mode.Format, D3DUSAGE_DEPTHSTENCIL , D3DRTYPE_SURFACE , D3DFMT_D24X8 )))
	{
		if (SUCCEEDED( m_pD3D->CheckDepthStencilMatch ( AdapterOrdinal, DevType, Mode.Format, Mode.Format, D3DFMT_D24X8 ))) return D3DFMT_D24X8;
		TraceGame(L"(INFO)INIT DIRECTX : Hardware is only support 24 bit depth buffer");
	} 

	// Check 24bit depth buffer available
	if (SUCCEEDED( m_pD3D->CheckDeviceFormat(AdapterOrdinal, DevType, Mode.Format, D3DUSAGE_DEPTHSTENCIL , D3DRTYPE_SURFACE , D3DFMT_D16 )))
	{
		if (SUCCEEDED( m_pD3D->CheckDepthStencilMatch ( AdapterOrdinal, DevType, Mode.Format, Mode.Format, D3DFMT_D16 ))) return D3DFMT_D16;
		TraceGame(L"(INFO)INIT DIRECTX : Hardware is only support 16 bit depth buffer");
	} 
	// No depth buffer supported
	TraceGame(L"(INFO)INIT DIRECTX :Hardware isn't support depth buffer");
	return D3DFMT_UNKNOWN;

}